package com.franklin.ideaplugin.easytesting.controllerclient.support;

import com.franklin.ideaplugin.easytesting.controllerclient.ControllerClientFactoryBean;
import com.franklin.ideaplugin.easytesting.controllerclient.utils.ControllerUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


/**
 * @author Ye Junhui
 * @since 2023/6/24 17:47
 */
@RequiredArgsConstructor
public class ControllerClientRegistrar implements BeanPostProcessor, BeanDefinitionRegistryPostProcessor, ApplicationContextAware {

    private BeanDefinitionRegistry beanDefinitionRegistry;
    private ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        this.beanDefinitionRegistry = registry;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (!ControllerUtil.isControllerBean(bean)) {
            return bean;
        }

        //注册feign客户端
        registerControllerClient(bean);
        return bean;
    }

    private void registerControllerClient(Object bean) {
        //避免aop改变类信息
        Class clazz = AopProxyUtils.ultimateTargetClass(bean);

        //代理类
        Class proxyClazz = ControllerUtil.buildControllerInterface(clazz);
        ControllerClientFactoryBean controllerClientFactoryBean = new ControllerClientFactoryBean(clazz,proxyClazz,applicationContext);

        BeanDefinitionBuilder definition = BeanDefinitionBuilder
                .genericBeanDefinition(proxyClazz, controllerClientFactoryBean::getObject);

        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        definition.setLazyInit(false);

        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        String proxyName = proxyClazz.getCanonicalName();
        beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, proxyName);
        beanDefinition.setAttribute("controllerClientsRegistrarFactoryBean", controllerClientFactoryBean);
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, proxyName, null);
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, beanDefinitionRegistry);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
